//
//  Home.swift
//  FullScreenCover
//
//  Created by alanzhangg on 2023/6/10.
//

import SwiftUI

struct Home: View {
    
    ///view Properties
    @State private var show: Bool = false
    @State private var selectedRow: Row = .init(color: .clear)
    @Namespace private var animation
    @GestureState var isdes = false
    
    var longges: some Gesture{
        LongPressGesture()
            .updating($isdes) { sd, adsa, asd in
                
            }
    }
    
    var body: some View {
        ScrollView(.vertical, showsIndicators: false) {
            LazyVGrid(columns: Array(repeating: .init(.flexible(), spacing: 5), count: 3), spacing: 5, content: {
                ForEach(rows) { row in
                    Rectangle()
                        .fill(row.color.gradient)
                        .frame(height: /*@START_MENU_TOKEN@*/100/*@END_MENU_TOKEN@*/)
                        .onTapGesture {
                            selectedRow = row
                            show.toggle()
                        }
                    
                }
            })
            .padding(15)
        }
        .heroFullScreenCover(show: $show) {
            ///detail view
            DetailView(row: $selectedRow, animationID: animation)
        }
    }
}

#Preview {
    ContentView()
}

///custom view modifier extention
extension View{
    @ViewBuilder
    func heroFullScreenCover<Content: View>(show: Binding<Bool>, @ViewBuilder content: @escaping () -> Content) -> some View{
        self
            .modifier(HelperHeroView(show: show, overlay: content()))
        
    }
}

///Helper Modifier

fileprivate struct HelperHeroView<Overlay: View>: ViewModifier{
    @Binding var show: Bool
    var overlay: Overlay
    
    ///view properties
    @State private var hostView: UIHostingController<Overlay>?
    @State private var parentController: UIViewController?
    
    func body(content: Content) -> some View {
        content
            .background(content: {
                ExtractSwiftUIParentController(content: overlay, hostView: $hostView) { viewController in
                    parentController = viewController
                }
            })
        ///initializing host view
            .onAppear{
                hostView = UIHostingController(rootView: overlay)
                
            }
        ///present/dismissing host view based on show state
            .onChange(of: show) { oldValue, newValue in
                if newValue {
                    ///present view
                    if let hostView {
                        ///changing presentation style and transition style
                        hostView.modalPresentationStyle = .overCurrentContext
                        hostView.modalTransitionStyle = .crossDissolve
                        hostView.view.backgroundColor = .clear
                        ///we need a parent view controller ti present it
                        parentController?.present(hostView, animated: false)
                    }
                }else{
                    ///dismiss view
                    hostView?.dismiss(animated: false)
                }
            }
    }
    
}

fileprivate struct ExtractSwiftUIParentController<Content: View>: UIViewRepresentable{
    var content: Content
    @Binding var hostView: UIHostingController<Content>?
    var parentController: (UIViewController?) -> ()
    
    func makeUIView(context: Context) -> UIView {
        ///simply return empty view
        return UIView()
    }
    
    func updateUIView(_ uiView: UIViewType, context: Context) {
        ///update hostview's rootview
        hostView?.rootView = content
        DispatchQueue.main.async {
            ///retrieve it's parent view controller
            parentController(uiView.superview?.superview?.parentController)
        }
    }
}

public extension UIView{
    var parentController: UIViewController?{
        var responder = self.next
        while responder != nil{
            if let viewController = responder as? UIViewController{
                return viewController
            }
            responder = responder?.next
        }
        return nil
    }
}

